﻿#include "StdAfx.h"
#include "UIWebBrowser.h"
#include <atlconv.h>
#include <atlcomcli.h>
#include "Internal/IEDownloadMgr.h"
#include <mshtml.h>

namespace DuiLib {
    ////////////////////////////////////////////////////////////////////////
    //
    IMPLEMENT_DUICONTROL(CWebBrowserUI)

    CWebBrowserUI::CWebBrowserUI()
        : m_pWebBrowser2(NULL)
        , _pHtmlWnd2(NULL)
        , m_pWebBrowserEventHandler(NULL)
        , m_bAutoNavi(false)
        , m_dwRef(0)
        , m_dwCookie(0) {
        m_clsid = CLSID_WebBrowser;
        m_sHomePage.Empty();
    }

    bool CWebBrowserUI::DoCreateControl() {
        if (!CActiveXUI::DoCreateControl())
            return false;

        GetManager()->AddTranslateAccelerator(this);
        GetControl(IID_IWebBrowser2, (LPVOID *)&m_pWebBrowser2);

        if ( m_bAutoNavi && !m_sHomePage.IsEmpty()) {
            this->Navigate2(m_sHomePage);
        }

        RegisterEventHandler(TRUE);
        return true;
    }

    void CWebBrowserUI::ReleaseControl() {
        m_bCreated = false;
        GetManager()->RemoveTranslateAccelerator(this);
        RegisterEventHandler(FALSE);
    }

    CWebBrowserUI::~CWebBrowserUI() {
        ReleaseControl();
    }

    STDMETHODIMP CWebBrowserUI::GetTypeInfoCount( UINT *iTInfo ) {
        *iTInfo = 0;
        return E_NOTIMPL;
    }

    STDMETHODIMP CWebBrowserUI::GetTypeInfo( UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo ) {
        return E_NOTIMPL;
    }

    STDMETHODIMP CWebBrowserUI::GetIDsOfNames( REFIID riid, OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId ) {
        return E_NOTIMPL;
    }

    STDMETHODIMP CWebBrowserUI::Invoke( DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr ) {
        if ((riid != IID_NULL))
            return E_INVALIDARG;

        switch(dispIdMember) {
            case DISPID_BEFORENAVIGATE2:
                BeforeNavigate2(
                    pDispParams->rgvarg[6].pdispVal,
                    pDispParams->rgvarg[5].pvarVal,
                    pDispParams->rgvarg[4].pvarVal,
                    pDispParams->rgvarg[3].pvarVal,
                    pDispParams->rgvarg[2].pvarVal,
                    pDispParams->rgvarg[1].pvarVal,
                    pDispParams->rgvarg[0].pboolVal);
                break;

            case DISPID_COMMANDSTATECHANGE:
                CommandStateChange(
                    pDispParams->rgvarg[1].lVal,
                    pDispParams->rgvarg[0].boolVal);
                break;

            case DISPID_NAVIGATECOMPLETE2:
                NavigateComplete2(
                    pDispParams->rgvarg[1].pdispVal,
                    pDispParams->rgvarg[0].pvarVal);
                break;

            case DISPID_NAVIGATEERROR:
                NavigateError(
                    pDispParams->rgvarg[4].pdispVal,
                    pDispParams->rgvarg[3].pvarVal,
                    pDispParams->rgvarg[2].pvarVal,
                    pDispParams->rgvarg[1].pvarVal,
                    pDispParams->rgvarg[0].pboolVal);
                break;

            case DISPID_STATUSTEXTCHANGE:
                break;

            //      case DISPID_NEWWINDOW2:
            //          break;
            case DISPID_NEWWINDOW3:
                NewWindow3(
                    pDispParams->rgvarg[4].ppdispVal,
                    pDispParams->rgvarg[3].pboolVal,
                    pDispParams->rgvarg[2].uintVal,
                    pDispParams->rgvarg[1].bstrVal,
                    pDispParams->rgvarg[0].bstrVal);
                break;

            case DISPID_TITLECHANGE: {
                TitleChange(pDispParams->rgvarg[0].bstrVal);
                break;
            }

            case DISPID_DOCUMENTCOMPLETE: {
                DocumentComplete(
                    pDispParams->rgvarg[1].pdispVal,
                    pDispParams->rgvarg[0].pvarVal);

                break;
            }

            default:
                return DISP_E_MEMBERNOTFOUND;
        }

        return S_OK;
    }

    STDMETHODIMP CWebBrowserUI::QueryInterface( REFIID riid, LPVOID *ppvObject ) {
        *ppvObject = NULL;

        if( riid == IID_IDocHostUIHandler)
            *ppvObject = static_cast<IDocHostUIHandler *>(this);
        else if( riid == IID_IDispatch)
            *ppvObject = static_cast<IDispatch *>(this);
        else if( riid == IID_IServiceProvider)
            *ppvObject = static_cast<IServiceProvider *>(this);
        else if(riid == IID_IInternetSecurityManager ) {
            *ppvObject = static_cast<IInternetSecurityManager *>(this);
        } else if (riid == IID_IOleCommandTarget)
            *ppvObject = static_cast<IOleCommandTarget *>(this);

        if( *ppvObject != NULL )
            AddRef();

        return *ppvObject == NULL ? E_NOINTERFACE : S_OK;
    }

    STDMETHODIMP_(ULONG) CWebBrowserUI::AddRef() {
        InterlockedIncrement(&m_dwRef);
        return m_dwRef;
    }

    STDMETHODIMP_(ULONG) CWebBrowserUI::Release() {
        ULONG ulRefCount = InterlockedDecrement(&m_dwRef);
        return ulRefCount;
    }

    void CWebBrowserUI::Navigate2( LPCTSTR lpszUrl ) {
        if (lpszUrl == NULL)
            return;

        if (m_pWebBrowser2) {
            CDuiVariant url;
            url.vt = VT_BSTR;
            url.bstrVal = T2BSTR(lpszUrl);
            HRESULT hr = m_pWebBrowser2->Navigate2(&url, NULL, NULL, NULL, NULL);
        }
    }

    void CWebBrowserUI::Refresh() {
        if (m_pWebBrowser2) {
            m_pWebBrowser2->Refresh();
        }
    }
    void CWebBrowserUI::GoBack() {
        if (m_pWebBrowser2) {
            m_pWebBrowser2->GoBack();
        }
    }
    void CWebBrowserUI::GoForward() {
        if (m_pWebBrowser2) {
            m_pWebBrowser2->GoForward();
        }
    }
    /// DWebBrowserEvents2
    void CWebBrowserUI::BeforeNavigate2( IDispatch *pDisp, VARIANT *&url, VARIANT *&Flags, VARIANT *&TargetFrameName, VARIANT *&PostData, VARIANT *&Headers, VARIANT_BOOL *&Cancel ) {
        if (m_pWebBrowserEventHandler) {
            m_pWebBrowserEventHandler->BeforeNavigate2(this, pDisp, url, Flags, TargetFrameName, PostData, Headers, Cancel);
        }
    }

    void CWebBrowserUI::NavigateError( IDispatch *pDisp, VARIANT *&url, VARIANT *&TargetFrameName, VARIANT *&StatusCode, VARIANT_BOOL *&Cancel ) {
        if (m_pWebBrowserEventHandler) {
            m_pWebBrowserEventHandler->NavigateError(this, pDisp, url, TargetFrameName, StatusCode, Cancel);
        }
    }

    void CWebBrowserUI::NavigateComplete2( IDispatch *pDisp, VARIANT *&url ) {
        CComPtr<IDispatch> spDoc;
        m_pWebBrowser2->get_Document(&spDoc);

        if (spDoc) {
            CComQIPtr<ICustomDoc, &IID_ICustomDoc> spCustomDoc(spDoc);

            if (spCustomDoc)
                spCustomDoc->SetUIHandler(this);
        }

        if (m_pWebBrowserEventHandler) {
            m_pWebBrowserEventHandler->NavigateComplete2(this, pDisp, url);
        }
    }

    void CWebBrowserUI::ProgressChange( LONG nProgress, LONG nProgressMax ) {
        if (m_pWebBrowserEventHandler) {
            m_pWebBrowserEventHandler->ProgressChange(this, nProgress, nProgressMax);
        }
    }

    void CWebBrowserUI::NewWindow3( IDispatch **pDisp, VARIANT_BOOL *&Cancel, DWORD dwFlags, BSTR bstrUrlContext, BSTR bstrUrl ) {
        if (m_pWebBrowserEventHandler) {
            m_pWebBrowserEventHandler->NewWindow3(this, pDisp, Cancel, dwFlags, bstrUrlContext, bstrUrl);
        }
    }
    void CWebBrowserUI::CommandStateChange(long Command, VARIANT_BOOL Enable) {
        if (m_pWebBrowserEventHandler) {
            m_pWebBrowserEventHandler->CommandStateChange(this, Command, Enable);
        }
    }

    void CWebBrowserUI::TitleChange(BSTR bstrTitle) {
        if (m_pWebBrowserEventHandler) {
            m_pWebBrowserEventHandler->TitleChange(this, bstrTitle);
        }
    }

    void CWebBrowserUI::DocumentComplete(IDispatch *pDisp, VARIANT *&url) {
        if (m_pWebBrowserEventHandler) {
            m_pWebBrowserEventHandler->DocumentComplete(this, pDisp, url);
        }
    }

    // IDownloadManager
    STDMETHODIMP CWebBrowserUI::Download( /* [in] */ IMoniker *pmk, /* [in] */ IBindCtx *pbc, /* [in] */ DWORD dwBindVerb, /* [in] */ LONG grfBINDF, /* [in] */ BINDINFO *pBindInfo, /* [in] */ LPCOLESTR pszHeaders, /* [in] */ LPCOLESTR pszRedir, /* [in] */ UINT uiCP ) {
        if (m_pWebBrowserEventHandler) {
            return m_pWebBrowserEventHandler->Download(this, pmk, pbc, dwBindVerb, grfBINDF, pBindInfo, pszHeaders, pszRedir, uiCP);
        }

        return S_OK;
    }

    // IDocHostUIHandler
    STDMETHODIMP CWebBrowserUI::ShowContextMenu( DWORD dwID, POINT *pptPosition, IUnknown *pCommandTarget, IDispatch *pDispatchObjectHit ) {
        if (m_pWebBrowserEventHandler) {
            return m_pWebBrowserEventHandler->ShowContextMenu(this, dwID, pptPosition, pCommandTarget, pDispatchObjectHit);
        }

        return S_FALSE;
    }

    STDMETHODIMP CWebBrowserUI::GetHostInfo( DOCHOSTUIINFO *pInfo ) {
        if (pInfo != NULL) {
            pInfo->dwFlags |= DOCHOSTUIFLAG_NO3DBORDER | DOCHOSTUIFLAG_NO3DOUTERBORDER;
        }

        if (m_pWebBrowserEventHandler) {
            return m_pWebBrowserEventHandler->GetHostInfo(this, pInfo);
        }

        return S_OK;
    }

    STDMETHODIMP CWebBrowserUI::ShowUI( DWORD dwID, IOleInPlaceActiveObject *pActiveObject, IOleCommandTarget *pCommandTarget, IOleInPlaceFrame *pFrame, IOleInPlaceUIWindow *pDoc ) {
        if (m_pWebBrowserEventHandler) {
            return m_pWebBrowserEventHandler->ShowUI(this, dwID, pActiveObject, pCommandTarget, pFrame, pDoc);
        }

        return S_OK;
    }

    STDMETHODIMP CWebBrowserUI::HideUI() {
        if (m_pWebBrowserEventHandler) {
            return m_pWebBrowserEventHandler->HideUI(this);
        }

        return S_OK;
    }

    STDMETHODIMP CWebBrowserUI::UpdateUI() {
        if (m_pWebBrowserEventHandler) {
            return m_pWebBrowserEventHandler->UpdateUI(this);
        }

        return S_OK;
    }

    STDMETHODIMP CWebBrowserUI::EnableModeless( BOOL fEnable ) {
        if (m_pWebBrowserEventHandler) {
            return m_pWebBrowserEventHandler->EnableModeless(this, fEnable);
        }

        return E_NOTIMPL;
    }

    STDMETHODIMP CWebBrowserUI::OnDocWindowActivate( BOOL fActivate ) {
        if (m_pWebBrowserEventHandler) {
            return m_pWebBrowserEventHandler->OnDocWindowActivate(this, fActivate);
        }

        return E_NOTIMPL;
    }

    STDMETHODIMP CWebBrowserUI::OnFrameWindowActivate( BOOL fActivate ) {
        if (m_pWebBrowserEventHandler) {
            return m_pWebBrowserEventHandler->OnFrameWindowActivate(this, fActivate);
        }

        return E_NOTIMPL;
    }

    STDMETHODIMP CWebBrowserUI::ResizeBorder( LPCRECT prcBorder, IOleInPlaceUIWindow *pUIWindow, BOOL fFrameWindow ) {
        if (m_pWebBrowserEventHandler) {
            return m_pWebBrowserEventHandler->ResizeBorder(this, prcBorder, pUIWindow, fFrameWindow);
        }

        return E_NOTIMPL;
    }

    STDMETHODIMP CWebBrowserUI::TranslateAccelerator( LPMSG lpMsg, const GUID *pguidCmdGroup, DWORD nCmdID ) {
        if (m_pWebBrowserEventHandler) {
            return m_pWebBrowserEventHandler->TranslateAccelerator(this, lpMsg, pguidCmdGroup, nCmdID);
        }

        return S_FALSE;
    }

    LRESULT CWebBrowserUI::TranslateAccelerator( MSG *pMsg ) {
        if(pMsg->message < WM_KEYFIRST || pMsg->message > WM_KEYLAST)
            return S_FALSE;

        if( m_pWebBrowser2 == NULL )
            return E_NOTIMPL;

        // 当前Web窗口不是焦点,不处理加速键
        BOOL bIsChild = FALSE;
        HWND hTempWnd = NULL;
        HWND hWndFocus = ::GetFocus();

        hTempWnd = hWndFocus;

        while(hTempWnd != NULL) {
            if(hTempWnd == m_hwndHost) {
                bIsChild = TRUE;
                break;
            }

            hTempWnd = ::GetParent(hTempWnd);
        }

        if(!bIsChild)
            return S_FALSE;

        IOleInPlaceActiveObject *pObj;

        if (FAILED(m_pWebBrowser2->QueryInterface(IID_IOleInPlaceActiveObject, (LPVOID *)&pObj)))
            return S_FALSE;

        HRESULT hResult = pObj->TranslateAccelerator(pMsg);
        pObj->Release();
        return hResult;
    }

    STDMETHODIMP CWebBrowserUI::GetOptionKeyPath( LPOLESTR *pchKey, DWORD dwReserved ) {
        if (m_pWebBrowserEventHandler) {
            return m_pWebBrowserEventHandler->GetOptionKeyPath(this, pchKey, dwReserved);
        }

        return E_NOTIMPL;
    }

    STDMETHODIMP CWebBrowserUI::GetDropTarget( IDropTarget *pDropTarget, IDropTarget **ppDropTarget ) {
        if (m_pWebBrowserEventHandler) {
            return m_pWebBrowserEventHandler->GetDropTarget(this, pDropTarget, ppDropTarget);
        }

        return S_FALSE; // 使用系统拖拽
    }

    STDMETHODIMP CWebBrowserUI::GetExternal( IDispatch **ppDispatch ) {
        if (m_pWebBrowserEventHandler) {
            return m_pWebBrowserEventHandler->GetExternal(this, ppDispatch);
        }

        return S_FALSE;
    }

    STDMETHODIMP CWebBrowserUI::TranslateUrl( DWORD dwTranslate, OLECHAR *pchURLIn, OLECHAR **ppchURLOut ) {
        if (m_pWebBrowserEventHandler) {
            return m_pWebBrowserEventHandler->TranslateUrl(this, dwTranslate, pchURLIn, ppchURLOut);
        } else {
            *ppchURLOut = 0;
            return E_NOTIMPL;
        }
    }

    STDMETHODIMP CWebBrowserUI::FilterDataObject( IDataObject *pDO, IDataObject **ppDORet ) {
        if (m_pWebBrowserEventHandler) {
            return m_pWebBrowserEventHandler->FilterDataObject(this, pDO, ppDORet);
        } else {
            *ppDORet = 0;
            return E_NOTIMPL;
        }
    }

    void CWebBrowserUI::SetWebBrowserEventHandler( CWebBrowserEventHandler *pEventHandler ) {
        if ( pEventHandler != NULL && m_pWebBrowserEventHandler != pEventHandler)
            m_pWebBrowserEventHandler = pEventHandler;
    }

    void CWebBrowserUI::Refresh2( int Level ) {
        CDuiVariant vLevel;
        vLevel.vt = VT_I4;
        vLevel.intVal = Level;
        m_pWebBrowser2->Refresh2(&vLevel);
    }

    void CWebBrowserUI::SetAttribute( LPCTSTR pstrName, LPCTSTR pstrValue ) {
        if (_tcsicmp(pstrName, _T("homepage")) == 0) {
            m_sHomePage = pstrValue;
        } else if (_tcsicmp(pstrName, _T("autonavi")) == 0) {
            m_bAutoNavi = (_tcsicmp(pstrValue, _T("true")) == 0);
        } else
            CActiveXUI::SetAttribute(pstrName, pstrValue);
    }

    void CWebBrowserUI::NavigateHomePage() {
        if (!m_sHomePage.IsEmpty())
            this->NavigateUrl(m_sHomePage);
    }

    void CWebBrowserUI::NavigateUrl( LPCTSTR lpszUrl ) {
        if (m_pWebBrowser2 && lpszUrl) {
            m_pWebBrowser2->Navigate((BSTR)SysAllocString(T2BSTR(lpszUrl)), NULL, NULL, NULL, NULL);
        }
    }

    LPCTSTR CWebBrowserUI::GetClass() const {
        return DUI_CTR_WEBBROWSER;
    }

    LPVOID CWebBrowserUI::GetInterface( LPCTSTR pstrName ) {
        if( _tcsicmp(pstrName, DUI_CTR_WEBBROWSER) == 0 ) return static_cast<CWebBrowserUI *>(this);

        return CActiveXUI::GetInterface(pstrName);
    }

    void CWebBrowserUI::SetHomePage( LPCTSTR lpszUrl ) {
        m_sHomePage.Format(_T("%s"), lpszUrl);
    }

    LPCTSTR CWebBrowserUI::GetHomePage() {
        return m_sHomePage;
    }

    void CWebBrowserUI::SetAutoNavigation( bool bAuto /*= TRUE*/ ) {
        if (m_bAutoNavi == bAuto) return;

        m_bAutoNavi = bAuto;
    }

    bool CWebBrowserUI::IsAutoNavigation() {
        return m_bAutoNavi;
    }

    STDMETHODIMP CWebBrowserUI::QueryService( REFGUID guidService, REFIID riid, void **ppvObject ) {
        HRESULT hr = E_NOINTERFACE;
        *ppvObject = NULL;

        if ( guidService == SID_SDownloadManager && riid == IID_IDownloadManager) {
            *ppvObject = this;
            return S_OK;
        }

        if(guidService == SID_SInternetSecurityManager && riid == IID_IInternetSecurityManager) {
            *ppvObject = this;
            return S_OK;
        }

        return hr;
    }

    HRESULT CWebBrowserUI::RegisterEventHandler( BOOL inAdvise ) {
        CComPtr<IWebBrowser2> pWebBrowser;
        CComPtr<IConnectionPointContainer>  pCPC;
        CComPtr<IConnectionPoint> pCP;
        HRESULT hr = GetControl(IID_IWebBrowser2, (void **)&pWebBrowser);

        if (FAILED(hr))
            return hr;

        hr = pWebBrowser->QueryInterface(IID_IConnectionPointContainer, (void **)&pCPC);

        if (FAILED(hr))
            return hr;

        hr = pCPC->FindConnectionPoint(DIID_DWebBrowserEvents2, &pCP);

        if (FAILED(hr))
            return hr;

        if (inAdvise) {
            hr = pCP->Advise((IDispatch *)this, &m_dwCookie);
        } else {
            hr = pCP->Unadvise(m_dwCookie);
        }

        return hr;
    }

    DISPID CWebBrowserUI::FindId( IDispatch *pObj, LPOLESTR pName ) {
        DISPID id = 0;

        if(FAILED(pObj->GetIDsOfNames(IID_NULL, &pName, 1, LOCALE_SYSTEM_DEFAULT, &id))) id = -1;

        return id;
    }

    HRESULT CWebBrowserUI::InvokeMethod( IDispatch *pObj, LPOLESTR pMehtod, VARIANT *pVarResult, VARIANT *ps, int cArgs ) {
        DISPID dispid = FindId(pObj, pMehtod);

        if(dispid == -1) return E_FAIL;

        DISPPARAMS dispparams;
        dispparams.cArgs = cArgs;
        dispparams.rgvarg = ps;
        dispparams.cNamedArgs = 0;
        dispparams.rgdispidNamedArgs = NULL;

        return pObj->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &dispparams, pVarResult, NULL, NULL);
    }

    HRESULT CWebBrowserUI::GetProperty( IDispatch *pObj, LPOLESTR pName, VARIANT *pValue ) {
        DISPID dispid = FindId(pObj, pName);

        if(dispid == -1) return E_FAIL;

        DISPPARAMS ps;
        ps.cArgs = 0;
        ps.rgvarg = NULL;
        ps.cNamedArgs = 0;
        ps.rgdispidNamedArgs = NULL;

        return pObj->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &ps, pValue, NULL, NULL);
    }

    HRESULT CWebBrowserUI::SetProperty( IDispatch *pObj, LPOLESTR pName, VARIANT *pValue ) {
        DISPID dispid = FindId(pObj, pName);

        if(dispid == -1) return E_FAIL;

        DISPPARAMS ps;
        ps.cArgs = 1;
        ps.rgvarg = pValue;
        ps.cNamedArgs = 0;
        ps.rgdispidNamedArgs = NULL;

        return pObj->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYPUT, &ps, NULL, NULL, NULL);
    }

    IDispatch *CWebBrowserUI::GetHtmlWindow() {
        IDispatch *pDp =  NULL;
        HRESULT hr;

        if (!m_pWebBrowser2)
            return NULL;

        hr = m_pWebBrowser2->get_Document(&pDp);

        if (FAILED(hr))
            return NULL;

        CComQIPtr<IHTMLDocument2> pHtmlDoc2 = pDp;

        if (pHtmlDoc2 == NULL)
            return NULL;

        hr = pHtmlDoc2->get_parentWindow(&_pHtmlWnd2);

        if (FAILED(hr))
            return NULL;

        IDispatch *pHtmlWindown = NULL;
        hr = _pHtmlWnd2->QueryInterface(IID_IDispatch, (void **)&pHtmlWindown);

        if (FAILED(hr))
            return NULL;

        return pHtmlWindown;
    }

    IWebBrowser2 *CWebBrowserUI::GetWebBrowser2( void ) {
        return m_pWebBrowser2;
    }

    HRESULT STDMETHODCALLTYPE CWebBrowserUI::QueryStatus( __RPC__in_opt const GUID *pguidCmdGroup, ULONG cCmds, __RPC__inout_ecount_full(cCmds ) OLECMD prgCmds[ ], __RPC__inout_opt OLECMDTEXT *pCmdText ) {
        HRESULT hr = OLECMDERR_E_NOTSUPPORTED;
        return hr;
    }

    HRESULT STDMETHODCALLTYPE CWebBrowserUI::Exec( __RPC__in_opt const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, __RPC__in_opt VARIANT *pvaIn, __RPC__inout_opt VARIANT *pvaOut ) {
        HRESULT hr = S_OK;

        if (pguidCmdGroup && IsEqualGUID(*pguidCmdGroup, CGID_DocHostCommandHandler)) {

            switch (nCmdID) {

                case OLECMDID_SHOWSCRIPTERROR: {
                    IHTMLDocument2             *pDoc = NULL;
                    IHTMLWindow2               *pWindow = NULL;
                    IHTMLEventObj              *pEventObj = NULL;
                    BSTR                        rgwszNames[5] = {
                        SysAllocString(L"errorLine"),
                        SysAllocString(L"errorCharacter"),
                        SysAllocString(L"errorCode"),
                        SysAllocString(L"errorMessage"),
                        SysAllocString(L"errorUrl")
                    };
                    DISPID                      rgDispIDs[5];
                    VARIANT                     rgvaEventInfo[5];
                    DISPPARAMS                  params;
                    BOOL                        fContinueRunningScripts = true;
                    int                         i;

                    params.cArgs = 0;
                    params.cNamedArgs = 0;

                    // Get the document that is currently being viewed.
                    hr = pvaIn->punkVal->QueryInterface(IID_IHTMLDocument2, (void **) &pDoc);
                    // Get document.parentWindow.
                    hr = pDoc->get_parentWindow(&pWindow);
                    pDoc->Release();
                    // Get the window.event object.
                    hr = pWindow->get_event(&pEventObj);

                    // Get the error info from the window.event object.
                    for (i = 0; i < 5; i++) {
                        // Get the property's dispID.
                        hr = pEventObj->GetIDsOfNames(IID_NULL, &rgwszNames[i], 1,
                                                      LOCALE_SYSTEM_DEFAULT, &rgDispIDs[i]);
                        // Get the value of the property.
                        hr = pEventObj->Invoke(rgDispIDs[i], IID_NULL,
                                               LOCALE_SYSTEM_DEFAULT,
                                               DISPATCH_PROPERTYGET, &params, &rgvaEventInfo[i],
                                               NULL, NULL);
                        SysFreeString(rgwszNames[i]);
                    }

                    // At this point, you would normally alert the user with
                    // the information about the error, which is now contained
                    // in rgvaEventInfo[]. Or, you could just exit silently.

                    (*pvaOut).vt = VT_BOOL;

                    if (fContinueRunningScripts) {
                        // Continue running scripts on the page.
                        (*pvaOut).boolVal = VARIANT_TRUE;
                    } else {
                        // Stop running scripts on the page.
                        (*pvaOut).boolVal = VARIANT_FALSE;
                    }

                    break;
                }

                default:
                    hr = OLECMDERR_E_NOTSUPPORTED;
                    break;
            }
        } else {
            hr = OLECMDERR_E_UNKNOWNGROUP;
        }

        return (hr);
    }
}